﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FunnyFunction
{
    public class MaJiang
    {
        public static List<List<mj>> BaseList = new List<List<mj>>();

        public static bool IsHu(List<mj> mjs)
        {
            // 先排序
            var lmjs = mjs.OrderBy(t => t.Index).ToArray();

            var dIndex = 0;
            for (int i = 0; i < lmjs.Length - 1; i++)
            {
                var cIndex = lmjs[i].Index;
                if (cIndex <= dIndex)
                {
                    continue;
                }
                dIndex = cIndex;
                if (lmjs[i + 1].Index == cIndex)
                {
                    var cmjs = lmjs.ToList();
                    BaseList.Clear();
                    BaseList.Add(new List<mj>());
                    BaseList[0].Add(cmjs[i + 1]);
                    cmjs.RemoveAt(i + 1);
                    BaseList[0].Add(cmjs[i]);
                    cmjs.RemoveAt(i);

                    if (TheckThree(cmjs))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        private static bool TheckThree(List<mj> cmjs)
        {
            while (cmjs.Count>0)
            {
                var index1 = cmjs[0].Index;
                if (cmjs[1].Index == index1 && cmjs[2].Index == index1)
                {
                    BaseList.Add(cmjs.Take(3).ToList());
                    cmjs = cmjs.Skip(3).ToList();
                    continue;
                }

                var i2 = cmjs.FirstOrDefault(t => t.Index == index1 + 1);
                var i3 = cmjs.FirstOrDefault(t => t.Index == index1 + 2);
                if (i2.Index == 0 || i3.Index == 0)
                {
                    return false;
                }
                BaseList.Add(new List<mj>());
                BaseList[BaseList.Count - 1].Add(cmjs[0]);
                cmjs.RemoveAt(0);
                BaseList[BaseList.Count - 1].Add(i2);
                cmjs.Remove(i2);
                BaseList[BaseList.Count - 1].Add(i3);
                cmjs.Remove(i3);
            }
            return true;
        }

        public static List<mj> GetHuList(List<mj> mjs)
        {
            List<mj> result = new List<mj>();

            // 第一种，假设无头
            foreach(var mj in mjs)
            {
                var nList = mjs.ToList();
                nList.Add(mj);
                if (IsHu(nList))
                    result.Add(mj);
            }

            // 第二种，假设有头
            // 先排序
            var lmjs = mjs.OrderBy(t => t.Index).ToArray();

            var dIndex = 0;
            for (int i = 0; i < lmjs.Length - 1; i++)
            {
                var cIndex = lmjs[i].Index;
                if (cIndex <= dIndex)
                {
                    continue;
                }
                dIndex = cIndex;
                if (lmjs[i + 1].Index == cIndex)
                {
                    var cmjs = lmjs.ToList();
                    BaseList.Clear();
                    BaseList.Add(new List<mj>());
                    BaseList[0].Add(cmjs[i + 1]);
                    cmjs.RemoveAt(i + 1);
                    BaseList[0].Add(cmjs[i]);
                    cmjs.RemoveAt(i);

                    if (TheckThreeNone(cmjs, out mj _mj))
                    {
                        result.Add(_mj);
                    }
                }
            }

            return result.Distinct().ToList();

        }

        private static bool TheckThreeNone(List<mj> cmjs, out mj mj)
        {
            mj = new mj(0);
            while (cmjs.Count > 0)
            {
                var index1 = cmjs[0].Index;

                if (cmjs.Count == 2)
                {
                    var index2 = cmjs[1].Index;
                    if (index1 == index2)
                    {
                        mj = new mj(index1);
                        break;
                    }
                    else if (index2 == index1 + 1)
                    {
                        mj = new mj(index1 + 2);
                        break;
                    }
                    else if (index2 == index1 + 2)
                    {
                        mj = new mj(index1 + 1);
                        break;
                    }
                    else
                        return false;
                }

                if (cmjs[1].Index == index1)
                {
                    if (cmjs[2].Index == index1)
                    {
                        BaseList.Add(cmjs.Take(3).ToList());
                        cmjs = cmjs.Skip(3).ToList();
                        continue;
                    }
                    else
                    {
                        if (mj.Index != 0)
                            return false;
                        else
                        {
                            mj = new mj(index1);
                            BaseList.Add(cmjs.Take(2).ToList());
                            cmjs = cmjs.Skip(2).ToList();
                            continue;
                        }
                    }
                }
                var i2 = cmjs.FirstOrDefault(t => t.Index == index1 + 1);
                var i3 = cmjs.FirstOrDefault(t => t.Index == index1 + 2);
                if (i2.Index == 0 && i3.Index == 0)
                {
                    return false;
                }

                if (i2.Index != 0 && i3.Index != 0)
                {
                    BaseList.Add(new List<mj>());
                    BaseList[BaseList.Count - 1].Add(cmjs[0]);
                    cmjs.RemoveAt(0);
                    BaseList[BaseList.Count - 1].Add(i2);
                    cmjs.Remove(i2);
                    BaseList[BaseList.Count - 1].Add(i3);
                    cmjs.Remove(i3);
                }
                else
                {
                    if (mj.Index != 0)
                        return false;

                    BaseList.Add(new List<mj>());
                    BaseList[BaseList.Count - 1].Add(cmjs[0]);
                    cmjs.RemoveAt(0);
                    if (i2.Index != 0)
                    {   // TO_DO 这种情况得考虑两头的情况，而且还不能是8910这样的
                        // 问题，这种情况下，是初始化判断，还是直接判断num的值
                        mj = new mj(index1 + 2);
                        BaseList[BaseList.Count - 1].Add(i2);
                        cmjs.Remove(i2);
                    }
                    else
                    {
                        mj = new mj(index1 + 1);
                        BaseList[BaseList.Count - 1].Add(i3);
                        cmjs.Remove(i3);
                    }
                }
            }
            return true;
        }
    }

    public struct mj
    {
        public MJColor color;

        public int Num;

        public mj(int Index)
        {
            var ci = Index / 10;
            var num = Index % 10;
            if (ci == 1 || ci == 2 || ci == 3)
            {
                if (num < 0)
                    throw new Exception("Error");
                color = (MJColor)ci;
                this.Num = num;
                return;
            }
            if (ci == 9)
            {
                if (num != 1 && num != 4 && num != 7)
                    throw new Exception("Error");

                color = MJColor.None;
                this.Num = num;
                return;
            }
            Num = 0;
            color = MJColor.None;
        }

        public int Index
        {
            get { return Num > 0 ? (int)color * 10 + Num : 0; }
        }

        private static string[] NumArr = new string[] { "", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
        public override string ToString()
        {
            switch (color)
            {
                case MJColor.Tong:
                    return "[" + NumArr[Num] + "筒]";
                case MJColor.Tiao:
                    return "[" + NumArr[Num] + "条]";
                case MJColor.Wan:
                    return "[" + NumArr[Num] + "万]";
                case MJColor.None:
                    {
                        switch (Num)
                        {
                            case 1:
                                return "[中]";
                            case 4:
                                return "[发]";
                            case 7:
                                return "[白]";
                            default:
                                break;
                        }
                    }
                    break;
                default:
                    break;
            }
            return "ERROR";
        }
    }

    public enum MJColor
    {
        Tong =1,
        Tiao =2,
        Wan =3,
        None = 9
    }
}
